/*
 * Rectangle.cpp
 *
 *  Created on: 23-11-2010
 *      Author: Przemek
 */

#include "geometry/Rectangle.hpp"
#include "utils/MathUtils.hpp"

namespace geometry
{

Rectangle::Rectangle(const Vector& position, const Dimension& size) :
	position(position), size(size)
{
}

Rectangle::Rectangle(const Rectangle& other) :
	position(other.position), size(other.size)
{
}

const Vector& Rectangle::getPosition() const
{
	return position;
}

void Rectangle::setPosition(const Vector& position)
{
	this->position = position;
}

const Dimension& Rectangle::getSize() const
{
	return size;
}

void Rectangle::setSize(const Dimension& size)
{
	this->size = size;
}

Rectangle Rectangle::translate(const Vector& vector) const
{
	return Rectangle(position + vector, size);
}

bool Rectangle::contains(const Vector& point) const
{
	float minX = position.getX();
	float minY = position.getY();
	float maxX = position.getX() + size.getWidth();
	float maxY = position.getY() + size.getHeight();

	if(minX > maxX)
	{
		std::swap(minX, maxX);
	}
	if(minY > maxY)
	{
		std::swap(minY, maxY);
	}

	const float x = point.getX();
	const float y = point.getY();

	return (x >= minX && x <= maxX && y >= minY && y <= maxY);
}

bool Rectangle::isEmpty() const
{
	return (MathUtils::isNearZero(size.getWidth()) || (MathUtils::isNearZero(size.getHeight())));
}

Vector Rectangle::getCenter() const
{
	return position + size.toVector() / 2.0f;
}

Vector Rectangle::getLeftCornerForCenteredDimension(const Dimension& dimension) const
{
	const float x = position.getX() + (size.getWidth() - dimension.getWidth()) / 2.0f;
	const float y = position.getY() + (size.getHeight() - dimension.getHeight()) / 2.0f;

	return Vector(x, y);
}

bool Rectangle::intersects(const Rectangle& other) const
{
	float left = position.getX();
	float oleft = other.getPosition().getX();
	float right = position.getX() + size.getWidth();
	float oright = other.getPosition().getX() + other.getSize().getWidth();
	float top = position.getY() + size.getHeight();
	float otop = other.getPosition().getY() + other.getSize().getHeight();
	float bottom = position.getY();
	float obottom = other.getPosition().getY();

	return (left < oright && right > oleft && top > obottom && bottom < otop);
}

bool Rectangle::intersects(const Line& line) const
{
	const Vector& topLeft = Vector(position.getX(), position.getY());
	const Vector& topRight = Vector(position.getX() + size.getWidth(), position.getY());
	const Vector& bottomLeft = Vector(position.getX(), position.getY() + size.getHeight());
	const Vector& bottomRight = Vector(position.getX() + size.getWidth(), position.getY()
			+ size.getHeight());
	const Line& top = Line(topLeft, topRight);
	const Line& bottom = Line(bottomLeft, bottomRight);
	const Line& left = Line(topLeft, bottomLeft);
	const Line& right = Line(topRight, bottomRight);

	if(line.intersects(top) || line.intersects(bottom) || line.intersects(left) || line.intersects(
			right))
	{
		return true;
	}
	return false;
}

Rectangle Rectangle::getIntersection(const Rectangle& other) const
{
	if(intersects(other))
	{
		float left = position.getX();
		float oleft = other.getPosition().getX();
		float right = position.getX() + size.getWidth();
		float oright = other.getPosition().getX() + other.getSize().getWidth();
		float top = position.getY() + size.getHeight();
		float otop = other.getPosition().getY() + other.getSize().getHeight();
		float bottom = position.getY();
		float obottom = other.getPosition().getY();

		float l = left > oleft? left : oleft;
		float t = top < otop? top : otop;
		float r = right < oright? right : oright;
		float b = bottom > obottom? bottom : obottom;

		Vector pos = Vector(l, b);

		return Rectangle(pos, Dimension(r - pos.getX(), t - pos.getY()));
	}
	return Rectangle(Vector(), Dimension(0, 0));
}

Rectangle& Rectangle::operator+=(const Vector& vector)
{
	position += vector;
	return *this;
}
Rectangle& Rectangle::operator-=(const Vector& vector)
{
	return operator +=(-vector);
}

Rectangle& Rectangle::operator=(const Rectangle& other)
{
	if(this != &other)
	{
		position = other.position;
		size = other.size;
	}
	return *this;
}

bool Rectangle::operator==(const Rectangle& other) const
{
	return (position == other.position && size == other.size);
}

bool Rectangle::operator!=(const Rectangle& other) const
{
	return !(operator==(other));
}

}
